class RangeList {
    constructor() {
        this.intervals = new Array();
    }

    checkParam(range) {
        if (!range instanceof Array) throw new Error('Illegal parameter.');
        if (range.length != 2) throw new Error('range\'s length must be 2');
        let [l, r] = range;
        if (!Number.isInteger(l) || !Number.isInteger(r)) throw new Error('range must be integers.');
        if (l > r) throw new Error('beginning of range must be less than end of range.');
        return;
    }
    /**
     * Adds a range to the list
     * @param {Array<number>} range - Array of two integers that specify
     beginning and end of range.
    */
    add(range) {
        this.checkParam(range);
        let [l, r] = range;

        if (l == r) return;
        r--;

        let _l = l, _r = r, flag = 0;
        const _intervals = new Array();

        if (this.intervals.length == 0) {
            _intervals.push([_l, _r]);
            flag = 1; // 当前区间是否和谁都不相交
        }

        for (const v of this.intervals) {
            let [vl, vr] = v;
            // ...l......r...vl.....vr....
            if (vl > r + 1) { //  [_l, _r] 要加到当前列表的末尾，且最后不用补上
                _intervals.push([_l, _r]);
                flag = 1;
            }

            // 有交集，需要合并起来
            if ((vl >= l && vl <= r + 1) // .....l...vl....r.....
                || (vr >= l - 1 && vr <= r) // .....l....vr....r....
                || (vl <= l && vr >= r)     // ....vl...l....r...vr...
                || (vl >= l && vr <= r)) {  // .....l....vl....vr....r
                _l = Math.min(_l, vl);
                _r = Math.max(_r, vr);
            } else {
                _intervals.push([vl, vr]); // vl....vr....l.....r
            }
        }

        if (!flag) _intervals.push([_l, _r]);
        this.intervals = _intervals;

    }
    /**
     * Removes a range from the list
     * @param {Array<number>} range - Array of two integers that specify
     beginning and end of range.
     */
    remove(range) {
        this.checkParam(range);
        let [l, r] = range;
        if (l == r) return;
        r--;
        const _intervals = new Array();

        for (const v of this.intervals) {
            let [vl, vr] = v;
            if (vl >= l && vr <= r) continue; // ...l....vl....vr...r 不操作
            else if (vl >= l && vl <= r) { // ...l....vl...r...vr... 留下[r+1,vr)
                _intervals.push([r + 1, vr]);
            } else if (vr >= l && vr <= r) { // ....vl...l....vr....r... [vl,l)
                _intervals.push([vl, l - 1]);
            } else if (vl <= l && vr >= r) { // ....vl....l...r...vr.... 留下两边
                _intervals.push([vl, l - 1], [r + 1, vr]);
            } else { // 没关系，不操作
                _intervals.push([vl, vr]);
            }
        }

        this.intervals = _intervals;
    }

    /**
     * Prints out the list of ranges in the range list
     */
    print() {
        for (const v of this.intervals) {
            const [vl, vr] = v;
            process.stdout.write(`[${vl}, ${vr + 1}) `);
        }
        process.stdout.write("\n");
    }
}

module.exports = RangeList;

// Example run
const rl = new RangeList();
rl.add([1, 5]);
rl.print();
rl.add([10, 20]);
rl.print();
rl.add([20, 20]);
rl.print();
rl.add([20, 21]);
rl.print();
rl.add([2, 4]);
rl.print();
rl.add([3, 8]);
rl.print();
rl.remove([10, 10]);
rl.print();
rl.remove([10, 11]);
rl.print();
rl.remove([15, 17]);
rl.print();
rl.remove([3, 19]);
rl.print();
